package com.hb.vest;

import brut.directory.ZipUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;

public class XmlReplaceTools {

    private static String ANDROID_NAME = "android:name";
    private static String ANDROID_VALUE = "android:value";
    private static String ANDROID_SCHEME = "android:scheme";


    private static String UMENG_KEY = "UMENG_APPKEY";
    private static String TENCENT_AUTH_ID = "TENCENT_AUTH_ID";
    private static String RANGERSAPPLOG = "RANGERSAPPLOG";
    private static String APP_NAME = "app_name";

    /**
     * 存放 xml 解析出来的 key-value
     */
    public static HashMap<String, String> mKeyMap = new HashMap<>();


    /**
     * 初始化操作
     * 将 resource 中 key 映射到 map 中
     *
     * @param resourceXml XML 文件
     */
    public static void initKey(File resourceXml) {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance();
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(resourceXml);
            NodeList metaDataNodes = document.getElementsByTagName("meta-data");

            for (int index = 0; index < metaDataNodes.getLength(); index++) {
                Element element = (Element) metaDataNodes.item(index);
                NamedNodeMap nodeMap = element.getAttributes();
                String name = nodeMap.getNamedItem("name").getNodeValue();
                String value = nodeMap.getNamedItem("value").getNodeValue();
                mKeyMap.put(name, value);
            }

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }

    }


    /**
     * 替换 manifest 中的key
     * 由于 meta-data 中的 key 与 资源文件中 xml 的meta-data key 会对应，不需要做额外处理
     * 但是其他标签下的 就需要做 key 的转换
     *
     * @param decodeApkDir apktool 解压好的文件夹路径
     */
    public static void replaceManifest(File decodeApkDir) {

        File manifestFile = new File(decodeApkDir.getPath(), "AndroidManifest.xml");

        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance();
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(manifestFile);
            NodeList metaDataNodes = document.getElementsByTagName("meta-data");
            // 替换 meta-data 中的数据
            for (int i = 0; i < metaDataNodes.getLength(); i++) {
                Element e = (Element) metaDataNodes.item(i);
                String key = e.getAttribute(ANDROID_NAME);
                if (mKeyMap.containsKey(key)) {
                    e.setAttribute(ANDROID_VALUE, mKeyMap.get(key));
                }
            }

            // 处理需要额外替换的数据 (非 meta-data)
            //<data/>
            NodeList dataNodes = document.getElementsByTagName("data");
            for (int index = 0; index < dataNodes.getLength(); index++) {
                Element e = (Element) dataNodes.item(index);
                String scheme = e.getAttribute(ANDROID_SCHEME);
                if (scheme.startsWith("um.")) {
                    // 友盟
                    e.setAttribute(ANDROID_SCHEME, "um." + mKeyMap.get(UMENG_KEY));
                } else if (scheme.startsWith("tencent")) {
                    // 腾讯真人认证
                    e.setAttribute(ANDROID_SCHEME, "tencent" + mKeyMap.get(TENCENT_AUTH_ID));
                } else if (scheme.startsWith("rangersapplog.")) {
                    // RANGERSAPPLOG
                    e.setAttribute(ANDROID_SCHEME, "rangersapplog." + mKeyMap.get(RANGERSAPPLOG));
                }
            }

            writeToXml(document, manifestFile);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }


    public static void replaceStringXml(File decodeApkDir) {
        File resDir = new File(decodeApkDir.getPath() + "/res/values/", "strings.xml");

        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance();
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(resDir);
            NodeList stringNodes = document.getElementsByTagName("string");
            for (int i = 0; i < stringNodes.getLength(); i++) {
                Element e = (Element) stringNodes.item(i);
                if (e.getAttribute("name").equals("tencent_auth_id")) {
                    e.getFirstChild().setNodeValue(mKeyMap.get(TENCENT_AUTH_ID));
                } else if (e.getAttribute("name").equals("bt")) {
                    e.getFirstChild().setNodeValue(mKeyMap.get(APP_NAME));
                }
            }
//            document.getElementsByTagName("string").item(1).getFirstChild().getNodeValue()


            writeToXml(document, resDir);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }

    public static void replacePackageName(String oldPackName, String newPackageName, File decodeApkDir) {
        File manifestFile = new File(decodeApkDir.getPath(), "AndroidManifest.xml");
        replaceStr(oldPackName, newPackageName, manifestFile);
    }


    /**
     * 写入 XML
     *
     * @param document
     * @param xmlFile
     * @throws TransformerException
     */
    private static void writeToXml(Document document, File xmlFile) throws TransformerException {
        document.getDocumentElement().normalize();
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(xmlFile);
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.transform(source, result);
    }

    private static void replaceStr(String oldString, String newString, File file) {
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {

            ArrayList<String> strings = new ArrayList<String>();
            String s;//读取的每一行数据
            while ((s = br.readLine()) != null) {
                if (s.contains(oldString)) {
                    s = s.replace(oldString, newString);
                }
                strings.add(s);//将数据存入集合
            }

            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            for (String string : strings) {
                bw.write(string);//一行一行写入数据
                bw.newLine();//换行
            }
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
